#include "PrecompiledHeader.h"
#include "Font.h"

/*--------------------------------------------------------------------------*/

Font::Font(const std::string& path, float size) :
	IResource("font:" + path + ":" + ::ToStr(size))
{
	this->m_path = path;
	this->m_size = size;

	/*--------------------------------------------------------------------------*/

	this->m_cache = NULL;
	this->m_widths = NULL;
}

/*--------------------------------------------------------------------------*/

Font::~Font()
{
	if (this->m_cache)
	{
		ROpenGL::DeleteTexture(&this->m_cache);
	}
}

/*--------------------------------------------------------------------------*/

void Font::Reload()
{
	if (this->m_cache != NULL)
	{
		delete this->m_cache;
		this->m_cache = NULL;
	}

	if (this->m_widths != NULL)
	{
		delete this->m_widths;
		this->m_widths = NULL;
	}

	this->CreateCache();
}

/*--------------------------------------------------------------------------*/

void Font::CreateCache()
{
	TTF_Font* ttffont = TTF_OpenFont(this->GetPath().c_str(), (int) this->m_size);
	AssertLogC(!ttffont, "Error during opening font: %s, Error message: %s", this->GetPath(), SDL_GetError());

	if (!ttffont)
	{
		return;
	}

	TTF_SetFontHinting(ttffont, 1);

	this->m_widths = new uint[96];
	SDL_Surface* letters[96];

	uint width = 0;
	uint height = (uint) this->m_size;

	SDL_Color sdl_c = { 255, 255, 255, 255 };

	for (uint i = 0; i < 96; ++i)
	{
		this->m_widths[i] = width;
		char c[] = { (char) i + 32, '\0'};
		letters[i] = TTF_RenderUTF8_Blended(ttffont, (char*) c, sdl_c);
		width += letters[i]->w;

		SDL_SetAlpha(letters[i], 0, 1);
	}

	SDL_Surface* surface = SDL_CreateRGBSurface(SDL_SWSURFACE, width, height, 32, 0x00ff0000, 0x0000ff00, 0x000000ff, 0xff000000);
	AssertLogC(!surface, "Error during creating new font surface: %s, Error message: %s", this->GetPath(), SDL_GetError());

	for (uint i = 0; i < 95; ++i)
	{
		SDL_Rect rect;
		rect.x = (Uint16) this->m_widths[i];
		rect.y = height - (letters[i]->h);
		rect.w = letters[i]->w;
		rect.h = (letters[i]->h);

		SDL_BlitSurface(letters[i], NULL, surface, &rect);
	}

	GLTextureDesc desc;
	desc.width = surface->w;
	desc.height = surface->h;
	desc.format = GL_RGBA;
	desc.internalFormat = GL_RGBA8;
	desc.type = GL_UNSIGNED_BYTE;
	desc.data = surface->pixels;

	std::stringstream sss;
	sss << "Font=" << this->m_path << "Size=" << this->m_size;
	desc.name = sss.str();

	this->m_cache = ROpenGL::GenTexture(&desc);

	ROpenGL::BindTextureAt(0, this->m_cache);
	glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
	glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);

	for (uint i = 0; i < 96; ++i)
	{
		SDL_FreeSurface(letters[i]);
	}

	SDL_FreeSurface(surface);
	TTF_CloseFont(ttffont);

	this->m_size = (float) this->m_cache->size.y;

	__super::Reload();
}

/*--------------------------------------------------------------------------*/

GLTexture* Font::GetTexture() const
{
	return this->m_cache;
}

/*--------------------------------------------------------------------------*/

float Font::GetLabelWidth(const std::string& content) const
{
	if (this->m_cache == NULL)
	{
		return 0.0f;
	}

	uint length = content.length();
	float margin = 0.0f;

	for (uint i = 0; i < length; ++i)
	{
		uchar char_to_render = content[i];

		if (char_to_render == ' ')
		{
			margin += this->m_size;
			continue;
		}

		uchar char_in_cache = char_to_render - 32;

		uint next_char_start = this->m_widths[char_in_cache + 1];
		uint char_start = this->m_widths[char_in_cache];

		float letterWidth = (float)(next_char_start - char_start);

		margin += letterWidth;
	}

	return margin;
}

/*--------------------------------------------------------------------------*/

const uint* Font::GetLettersWidths() const
{
	return this->m_widths;
}

/*--------------------------------------------------------------------------*/

float Font::GetSize() const
{
	return this->m_size;
}

/*--------------------------------------------------------------------------*/

void Font::SetSize(float size)
{
	this->m_size = size;
}

/*--------------------------------------------------------------------------*/

const std::string& Font::GetPath() const
{
	return this->m_path;
}

/*--------------------------------------------------------------------------*/

void Font::SetPath(const std::string& path)
{
	this->m_path = path;
}

/*--------------------------------------------------------------------------*/